/**************************************
Surround Pan [Build 131012] by Stige T.
**************************************/

desc:Surround Pan - Stereo To 5.1

in_pin:L
in_pin:R
in_pin:n/a
in_pin:n/a
in_pin:n/a
in_pin:n/a
out_pin:L Front
out_pin:R Front
out_pin:Center
out_pin:LF
out_pin:L Back
out_pin:R Back

slider1:50<0,100,0.1>Pan Left/Right
slider2:50<0,100,0.1>Pan Front/Back
slider3:-100<-100,12,0.5>Sum To Center [dB]
slider4:-100<-100,12,0.5>Sum To LFE [dB]
slider5:-3<-6,6,1>Pan Law [dB]
slider6:100<0,100,1>Input Width [%]
slider7:0<-120,12,1>Output Level [dB]
slider8:0<0,1,1{Separate,Include in Pan}>Center Channel
slider10:0<0,6,1{Free (mouse),Rotating,Cruising,Spiraling,Wandering,Bee In A Box,Square}>Mode
slider11:1<0,1,0.01>Amplitude X
slider12:1<0,1,0.01>Amplitude Y
slider13:0<-1,1,0.01>Offset X
slider14:0<-1,1,0.01>Offset Y
slider15:10<-60,60,0.1>Speed [RPM]

filename:0,surround_pan_gfx/bg.png
filename:1,surround_pan_gfx/dot.png

@init
coordinatelist = 1000;

function calc_pan_x(pos_x) (
  cmode ? (
    L = max((0.5-pos_x)/0.5,0);
    C = (-abs(1-((1-pos_x)/0.5))+1)*0.708;
    R = max((pos_x-0.5)/0.5,0);
  ) : (
    L = 1 - pos_x;
    R = pos_x;
    C = 0;
  );
);

function calc_pan_y(pos_y) (
  F = 1-pos_y;
  B = pos_y;
);

function execute_pan(pos_x,pos_y)
(
  pos_x = min(max(pos_x,0),1);
  pos_y = min(max(pos_y,0),1);
  
  compensateFB = 1-(1-abs(1-pos_y/0.5)) * (1-dbcmp);
  compensateLR = 1-(1-abs(1-pos_x/0.5)) * (1-dbcmp);
  
  calc_pan_x(pos_x);
  calc_pan_y(pos_y);
  
  slider1 = ((-L * 0.5) + 0.5 + (R * 0.5)) * 100;
  slider2 = B * 100;
  slider_automate(slider1);
  slider_automate(slider2);
  coordinatelist[0] = coordinatelist[1] = 0;
  coordinatelist[2] = coordinatelist[3] = coordinatelist[6] = coordinatelist[7] = 8;
  coordinatelist[4] = floor(500 * pos_x-4);
  coordinatelist[5] = floor(500 * pos_y-4);
);

function mouse_pan()
local(pos_x,pos_y)
(
  pos_x = min(max(mouse_x,0),500)/500;
  pos_y = min(max(mouse_y,0),500)/500;
  execute_pan(pos_x,pos_y);
);

function update_coords()
local(pos_x,pos_y)
(
  pos_x = slider1*5;
  pos_y = slider2*5;
  coordinatelist[0] = coordinatelist[1] = 0;
  coordinatelist[2] = coordinatelist[3] = coordinatelist[6] = coordinatelist[7] = 8;
  coordinatelist[4] = pos_x-4;
  coordinatelist[5] = pos_y-4;
);

function draw_bounds(amplitudeX,amplitudeY,offsetX,offsetY)
local(Ax1,Ax2,Ax3,Ay1,Ay2,Ay3)
(
  amplitudeX + amplitudeY != 2 ? (
    gfx_a = 0.3;
    //gfx_r = 1; gfx_g = 1; gfx_b = 0;
    Ax1 = (((offsetX*(1-amplitudeX)/2) + 0.5) * 500) - (amplitudeX/2*500);
    Ay1 = (((offsetY*(1-amplitudeY)/2) + 0.5) * 500) - (amplitudeY/2*500);
    Ax2 = (((offsetX*(1-amplitudeX)/2) + 0.5) * 500) + (amplitudeX/2*500);
    Ay2 = (((offsetY*(1-amplitudeY)/2) + 0.5) * 500) - (amplitudeY/2*500);
    Ax3 = (((offsetX*(1-amplitudeX)/2) + 0.5) * 500) + (amplitudeX/2*500);
    Ay3 = (((offsetY*(1-amplitudeY)/2) + 0.5) * 500) + (amplitudeY/2*500);
    gfx_x = Ax1;
    gfx_y = Ay1;
    gfx_lineto(Ax2,Ay2,0);
    gfx_lineto(Ax3,Ay3,0);
    gfx_lineto(Ax1,Ay3,0);
    gfx_lineto(Ax1,Ay1,0);
  );
);

function rotating(speed,amplitudeX,amplitudeY,offsetX,offsetY)
local(pos_x,pos_y,angle)
(
  pos_x = (offsetX*(1-amplitudeX)/2) + 0.5 + cos(angle*0.0174532925)*amplitudeX/2; 
  pos_y = (offsetY*(1-amplitudeY)/2) + 0.5 + sin(angle*0.0174532925)*amplitudeY/2;
  
  execute_pan(pos_x,pos_y);
  
  angle > 360 ? angle = 0 : angle += speed;    
);

function wandering(speed,amplitudeX,amplitudeY,offsetX,offsetY)
local(pos_x,pos_y,init,rand_x,rand_y,dir_x,dir_y,chooser)
(
  !init ? (
    pos_x = 0.5;
    pos_y = 0.5;
    init = 1;
    chooser = 1;
  );
  
  speed ? (
    speed = abs(speed/250);
    rand_x = rand(chooser);
    rand_x  == 0 ? dir_x = -speed;
    rand_x  == 1 ? dir_x = speed;
    pos_x += dir_x;
    pos_x < (offsetX*(1-amplitudeX)/2) + 0.5 - (amplitudeX/2) ? dir_x = speed*2; chooser = rand(6)+1;
    pos_x > (offsetX*(1-amplitudeX)/2) + 0.5 + (amplitudeX/2) ? dir_x = -speed*2; chooser = rand(6)+1;
  
    rand_y = rand(chooser);
    rand_y  == 0 ? dir_y = -speed;
    rand_y  == 1 ? dir_y = speed;
    pos_y += dir_y;
    pos_y < (offsetY*(1-amplitudeY)/2) + 0.5 - (amplitudeY/2) ? dir_y = speed*2; chooser = rand(6)+1;
    pos_y > (offsetY*(1-amplitudeY)/2) + 0.5 + (amplitudeY/2) ? dir_y = -speed*2; chooser = rand(6)+1;

    execute_pan(pos_x,pos_y);
  );
);

function cruising(speed,amplitudeX,amplitudeY,offsetX,offsetY)
local(pos_x,pos_y,angle,angle2,rand_x,rand_y)
( 
  speed ? (
    rand_x = (50-rand(100))/100000;
    rand_y = (50-rand(200))/100000;
    pos_x = (offsetX*(1-amplitudeX)/2) + 0.5 + cos(angle*0.0174532925)*amplitudeX/2; 
    pos_y = (offsetY*(1-amplitudeY)/2) + 0.5 + sin(angle2*0.0174532925)*amplitudeY/2;
  
    execute_pan(pos_x,pos_y);
  
    angle > 360 ? angle = 0 : angle += (speed + (sign(speed)*rand_x));  
    angle2 > 360 ? angle2 = 0 : angle2 += (speed + (sign(speed)*rand_y));
  );
);

function spiraling(speed,amplitudeX,amplitudeY,offsetX,offsetY)
local(pos_x,pos_y,angle,var,step)
( 

  speed ? (
    pos_x = (offsetX*(1-amplitudeX)/2) + 0.5 + cos(angle*0.0174532925)*(amplitudeX/2-(var*amplitudeX)); 
    pos_y = (offsetY*(1-amplitudeY)/2) + 0.5 + sin(angle*0.0174532925)*(amplitudeY/2-(var*amplitudeY));
  
    execute_pan(pos_x,pos_y);
  
    var <= 0 ? step = 0.000001;
    var > 1 ? step = -0.000001;
    var += step;
  
    angle > 360 ? angle = 0 : angle += speed;
  );

);

function beebox(speed,amplitudeX,amplitudeY,offsetX,offsetY)
local(pos_x,pos_y,angle,aVar,aVar2,aDir,aDir2,aRand,aRand2,oVar,oVar2,oDir,oDir2,oRand,oRand2,rspeed)
(

  !init ? (
    aVar = 0.65;
    aVar2 = 0.65;
    init = 1;
  );
 
  speed ? (
    bound1 = amplitudeX *= aVar;
    bound2 = amplitudeY *= aVar2;
    bound3 = offsetX += (oVar*(1-aVar));
    bound4 = offsetY += (oVar2*(1-aVar2));
  
    pos_x = (offsetX*(1-amplitudeX)/2) + 0.5 + cos(angle*0.0174532925)*(amplitudeX/2); 
    pos_y = (offsetY*(1-amplitudeY)/2) + 0.5 + sin(angle*0.0174532925)*(amplitudeY/2);
  
    execute_pan(pos_x,pos_y);
    
    rspeed = speed/500;
    
    aRand = rand(1);
    aRand  == 0 ? aDir = -rspeed;
    aRand  == 1 ? aDir = rspeed;
    aVar > 1 ? aDir = -aDir;
    aVar < 0.1 ? aDir = abs(aDir);
    aVar += aDir;
    
    aRand2 = rand(1);
    aRand2  == 0 ? aDir2 = -rspeed;
    aRand2  == 1 ? aDir2 = rspeed;
    aVar2 > 1 ? aDir2 = -aDir2;
    aVar2 < 0.1 ? aDir2 = abs(aDir2);
    aVar2 += aDir2;
    
    oRand = rand(3);
    oRand  == 0 ? oDir = -rspeed*2;
    oRand  == 1 ? oDir = rspeed*2;
    oVar > amplitudeX ? oDir = -oDir;
    oVar < -amplitudeX ? oDir = abs(oDir);
    oVar += oDir;
    
    oRand2 = rand(3);
    oRand2  == 0 ? oDir2 = -rspeed*2;
    oRand2  == 1 ? oDir2 = rspeed*2;
    oVar2 > amplitudeY ? oDir2 = -oDir2;
    oVar2 < -amplitudeY ? oDir2 = abs(oDir2);
    oVar2 += oDir2;
      
    angle > 360 ? angle = 0 : angle += speed;
  );
);

function square(speed,amplitudeX,amplitudeY,offsetX,offsetY)
local(pos_x,pos_y,sqx,sqy)
( 
  speed ? (
    
    speed = speed * (amplitudeX + amplitudeY)/2;
    
    pos_y <= 0 ? (
      pos_x += speed/75 / amplitudeX;
    );
    pos_x >= 1 ? (
      pos_y += speed/75 / amplitudeY;
    );
    pos_y >= 1 ? (
      pos_x -= speed/75 / amplitudeX;
    );
    pos_x <= 0 ? (
      pos_y -= speed/75 / amplitudeY;
    );
    
    sqx = (offsetX*(1-amplitudeX)/2) + ((1-amplitudeX)/2) + pos_x*amplitudeX; 
    sqy = (offsetY*(1-amplitudeY)/2) + ((1-amplitudeY)/2) + pos_y*amplitudeY;
     
    execute_pan(sqx,sqy);
     
  );
);

@slider

cmode = slider8;

dbcmp = 10 ^ ((slider5+6) / 20);
compensateLVL = 10 ^ (-slider5 / 20);
compensateFB = 1-(1-abs(1-slider2/50)) * (1-dbcmp);
compensateLR = 1-(1-abs(1-slider1/50)) * (1-dbcmp);
Output = 10 ^ (slider7 / 20);

calc_pan_x(slider1/100);
calc_pan_y(slider2/100);

slider3 == -100 ? (cmul = 0;) : (cmul = 10^(slider3/20););
slider4 == -100 ? (lfemul = 0;) : (lfemul = 10^(slider4/20););

slider1 || slider2 ? (update_coords(););

speed = 1/(srate/360) * (slider15/60);

@sample

W1 = (100-slider6)/100;
W2 = 1-(100-slider6)/100;
spl0 = (spl0*W2) + (spl1*W1);
spl1 = (spl1*W2) + (spl0*W1);

FL = spl0 * L * F;
FR = spl1 * R * F;
FC = (spl0+spl1)/2 * C * F;
SL = spl0 * (L+(C*0.708)) * B;
SR = spl1 * (R+(C*0.708)) * B;

cmode ? (spl2 = FC*compensateFB*compensateLR*compensateLVL*Output;) : (spl2 = ((spl0+spl1)/2)*cmul;);
spl3 = ((spl0+spl1)/2)*lfemul;

spl0 = FL*compensateFB*compensateLR*compensateLVL*Output;
spl1 = FR*compensateFB*compensateLR*compensateLVL*Output;
spl4 = SL*compensateFB*compensateLR*compensateLVL*Output;
spl5 = SR*compensateFB*compensateLR*compensateLVL*Output;

slider10 == 1 ? (
  rotating(speed,slider11,slider12,slider13,slider14);
);
slider10 == 2 ? (
  cruising(speed,slider11,slider12,slider13,slider14);
);
slider10 == 3 ? (
  spiraling(speed,slider11,slider12,slider13,slider14);
);
slider10 == 4 ? (
  wandering(speed,slider11,slider12,slider13,slider14);
);
slider10 == 5 ? (
  beebox(speed,slider11,slider12,slider13,slider14);
);
slider10 == 6 ? (
  square(speed,slider11,slider12,slider13,slider14);
);

@gfx 500 480

gfx_a = 1;
gfx_r = gfx_g = gfx_b = 1;
gfx_x = 0; gfx_y = 0;
gfx_blit(0,1,0);

slider10 > 0 ? (
  while (
    trail[i] = coordinatelist[4];
    trail[100+i] = coordinatelist[5];
    i += 1;
    i > 99 ? i = 0;
  );

  loop (100,
    gfx_x = trail[i2]+4;
    gfx_y = trail[100+i2]+4;
    gfx_setpixel(0,0.5,0);
    i2 += 1;
    i2 > 99 ? i2 = 0;
  );
) : (
  mouse_cap ? (mouse_pan(););
  mouse_cap & 4 ? (execute_pan(0.5,0.5););
);

gfx_blitext(1,coordinatelist,0);
gfx_r = 1; gfx_g = 1; gfx_b = 0;
draw_bounds(slider11,slider12,slider13,slider14);

slider10 == 5 ? (
  gfx_r = 0; gfx_g = 1; gfx_b = 1;
  draw_bounds(bound1,bound2,bound3,bound4);
);
